package com.tianji.learning.utils;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.JsonUtils;
import com.tianji.common.utils.ObjectUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import io.swagger.util.Json;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.DelayQueue;

/**
 * ClassName: LearningRecordDelayTaskHandler
 * Package: com.tianji.learning.utils
 * Description:
 *
 * @Author 陈宽
 * @Create 2025/7/1 22:13
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class LearningRecordDelayTaskHandler {
    private final StringRedisTemplate redisTemplate;
    private final String KEY_TEMPLATE = "learning:record:{}";
    private DelayQueue<DelayTask<DelayTaskData>> delayQueue = new DelayQueue();
    private final LearningRecordMapper recordMapper;
    private final LearningLessonMapper lessonMapper;
    private static Boolean flag = true;
    @PostConstruct
    public void init() {
        log.info("Bean初始化阶段执行");
//         new Thread(() -> handleDelayTask()).start();
        CompletableFuture.runAsync(this::handleDelayTask);
    }
    public Map<Long, LearningRecord> getAllRedisRecord(Long lessonId) {
        //1.组装 key
        String key = StringUtils.format(KEY_TEMPLATE, lessonId);
        Map<Long, LearningRecord> map = new HashMap<>();
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);
        entries.forEach(
                (k,v)->{
                    String hashKey = (String) k;
                    String hashValue = (String) v;
                    LearningRecord bean = JsonUtils.toBean(hashValue, LearningRecord.class);
                    map.put(Long.valueOf(hashKey), bean);
                }
        );
        return map;
    }

    private void handleDelayTask()  {
        try {
            while (flag){
                //1.不断的获取任务
                DelayTask<DelayTaskData> data = delayQueue.take();
                //2.从redis中获取数据
                LearningRecord learningRecord = readRedis(data.getData().getLessonId(), data.getData().getSectionId());

                //3.判断任务和redis实时数据里面的moment是否一致
                Boolean isSame = ObjectUtils.isEmpty(learningRecord) || !learningRecord.getMoment().equals(data.getData().getMoment());
                //4.不一致，则continue
                if (!isSame) {
                    continue;
                }
                //5.一致，则更新数据库
                //5.1更新record表
                learningRecord.setFinished(null);
                recordMapper.updateById(learningRecord);
                //5.2更新lesson表
                LearningLesson lesson = new LearningLesson();
                lesson.setId(data.getData().getLessonId());
                lesson.setLatestSectionId(data.getData().getSectionId());
                lesson.setLatestLearnTime(LocalDateTime.now().minusSeconds(20));
                lessonMapper.updateById(lesson);
            }
        } catch (InterruptedException e) {
            log.error("处理某个播放进度延时检测任务逻辑异常:{}", e);
        }
    }

    @PreDestroy
    public void destory(){
        flag = false;
    }
    /**
     * 删除redis中的数据
     * @param oldRecord
     */
    public void deleteRedis(LearningRecord oldRecord) {
        //1. 组装key
        String key = StringUtils.format(KEY_TEMPLATE, oldRecord.getLessonId());
        String hashKey = StringUtils.format("{}:{}", oldRecord.getLessonId(), oldRecord.getSectionId());
        //2. 删除数据
        redisTemplate.opsForHash().delete(key, hashKey);
    }

    /**
     * 添加延迟任务
     * @param record
     */
    public void addDelayTask(LearningRecord record) {
        log.info("添加redis实时数据,{}", record);
        writeRedis(record);
        log.info("添加延迟任务，学习记录数据：{}", record);
        DelayTaskData data = new DelayTaskData();
        data.setLessonId(record.getLessonId());
        data.setSectionId(record.getSectionId());
        data.setMoment(record.getMoment());
        delayQueue.add(new DelayTask<>(Duration.ofSeconds(20), data));
    }

    /**
     * 读取redis里面的数据
     * @param lessonId
     * @param sectionId
     * @return
     */
    public LearningRecord readRedis(Long lessonId, Long sectionId) {
        //组装 key
        String key = StringUtils.format(KEY_TEMPLATE, lessonId);
        //组装hashkey
        String hashKey = StringUtils.format("{}:{}", lessonId, sectionId);
        //获取数据
        String jsonStr = (String) redisTemplate.opsForHash().get(key, hashKey);
        if (ObjectUtils.isEmpty(jsonStr)){
            return null;
        }
        return JsonUtils.toBean(jsonStr, LearningRecord.class);
    }

    /**
     * 写入redis
     */
    public void writeRedis(LearningRecord learningRecord) {
        log.info("将学习记录写入缓存，学习记录数据：{}", learningRecord);
        // 1、组装大key learning:record:{}
        String key = StringUtils.format(KEY_TEMPLATE, learningRecord.getLessonId());

        // 2、组装hashkey
        String hashKey = StringUtils.format("{}:{}", learningRecord.getLessonId(), learningRecord.getSectionId());

        // 3、组装hashvalue
        String jsonStr = JsonUtils.toJsonStr(BeanUtils.toBean(learningRecord, RedisRecordData.class));

        // 4、写入缓存
        redisTemplate.opsForHash().put(key, hashKey, jsonStr);
        redisTemplate.expire(key, Duration.ofMinutes(1));
    }
    @Data
    class RedisRecordData {
        /**
         * 学习记录的id
         */
        private Long id;

        /**
         * 视频的当前观看时间点，单位秒
         */
        private Integer moment;

        /**
         * 是否完成学习，默认false
         */
        private Boolean finished;
    }

    @Data
    class DelayTaskData {
        /**
         * 课表ID
         */
        private Long lessonId;
        /**
         * 小节ID
         */
        private Long sectionId;
        /**
         * 视频的当前观看时间点，单位秒
         */
        private Integer moment;
    }
}
